package software

import (
	"context"
	"log"
	"time"

	amqp "github.com/rabbitmq/amqp091-go"
)

func NewRabbitMQ(ctx context.Context, uri string) *RabbitMQ {
	r := &RabbitMQ{
		ctx:         ctx,
		uri:         uri,
		contentType: "text/plain",
	}

	var err error

	r.connection, err = amqp.Dial(r.uri)
	if err != nil {
		panic(err)
	}
	defer func(connection *amqp.Connection) {
		err := connection.Close()
		if err != nil {
			panic(err)
		}
	}(r.connection)

	r.channel, err = r.connection.Channel()
	if err != nil {
		panic(err)
	}
	defer func(channel *amqp.Channel) {
		err := channel.Close()
		if err != nil {
			panic(err)
		}
	}(r.channel)

	r.queue, err = r.channel.QueueDeclare("hello", r.durable, r.autoDelete, r.exclusive, r.noWait, r.arguments)

	return r
}

type RabbitMQ struct {
	ctx         context.Context  // 上下文
	uri         string           // URL
	exchange    string           // Exchange
	mandatory   bool             // mandatory
	immediate   bool             // immediate 立即
	exclusive   bool             // exclusive 排他
	durable     bool             // durable 持久化
	noLocal     bool             // noLocal 不本地
	noWait      bool             // noWait 不等待
	autoAck     bool             // autoAck 自动应答
	autoDelete  bool             // autoDelete 自动删除
	contentType string           // contentType 内容类型
	arguments   amqp.Table       // arguments 参数
	connection  *amqp.Connection // connection 连接
	channel     *amqp.Channel    // channel 通道
	queue       amqp.Queue       // queue 队列
}

func (r *RabbitMQ) Publish(data []byte) {
	ctx, cancel := context.WithTimeout(r.ctx, 5*time.Second)
	defer cancel()

	err := r.channel.PublishWithContext(ctx, r.exchange, r.queue.Name, r.mandatory, r.immediate, amqp.Publishing{
		ContentType: r.contentType,
		Body:        data,
	})
	if err != nil {
		panic(err)
	}
}
func (r *RabbitMQ) Consume() {
	msgs, err := r.channel.Consume(r.queue.Name, "", r.autoAck, r.exclusive, r.noLocal, r.noWait, r.arguments)
	if err != nil {
		panic(err)
	}

	go func() {
		for d := range msgs {
			log.Printf("Received a message: %s", d.Body)
		}
	}()

	var forever chan struct{}
	<-forever
}
func main() {
	confirms := make(chan amqp.Confirmation)
	ch.NotifyPublish(confirms)
	go func() {
		for confirm := range confirms {
			if confirm.Ack {
				// code when messages is confirmed
				log.Printf("Confirmed")
			} else {
				// code when messages is nack-ed
				log.Printf("Nacked")
			}
		}
	}()

	err = ch.Confirm(false)
	failOnError(err, "Failed to confirm")

	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when unused
		false, // exclusive
		false, // no-wait
		nil,   // arguments
	)
}
